﻿using System;
using System.ComponentModel.Composition.Packaging;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using AdminApp.Web.Services;
using TheOliver.DigitalSignage.Client.Interfaces;
using TheOliver.DigitalSignage.Client.Logic;
using TheOliver.DigitalSignage.Client.Screens;

namespace TheOliver.DigitalSignage.Client.Controls
{
    public partial class Rotator : UserControl
    {
        ISlidePlaceholder _slidePlaceholder;
        ISlideStory _slideStory;
        IForeground _foreground;
        IBackground _background; 
        int _currentSlide = -1;
        private System.ComponentModel.Composition.Packaging.Package package;

        public Rotator()
        {
            InitializeComponent();
        }

        public event EventHandler ComponentsLoaded;

        private void CheckComponents()
        {
            if (_slidePlaceholder != null &&
                _slideStory != null &&
                _foreground != null &&
                _background != null)
            {
                if (ComponentsLoaded != null)
                {
                    ComponentsLoaded(this, EventArgs.Empty);
                }
            }
        }

        public void SetPackage(Package package)
        {
            this.package = package;

            _slidePlaceholder = null;
            _slideStory = null;
            _foreground = null;
            _background = null; 

            // Slide Story
            _slideStory = GetInstanceOfType(typeof(ISlideStory), typeof(DefaultSlideStory)) as ISlideStory;

            // Background
            var background = GetInstanceOfType(typeof(IBackground), typeof(DefaultBackground)) as FrameworkElement;
            background.Loaded += (s, e) =>
                {
                    _background = background as IBackground;
                    CheckComponents();
                };
            _backgroundPanel.Content = background;

            // SlidePlaceHolder
            var placeholder = GetInstanceOfType(typeof(ISlidePlaceholder), typeof(DefaultSlidePlaceholder)) as FrameworkElement;
            placeholder.Loaded += (s, e) =>
                {
                    _slidePlaceholder = placeholder as ISlidePlaceholder;
                    CheckComponents();
                };
            _slidePlaceHolderPanel.Content = placeholder;

            // Foreground
            var foreground = GetInstanceOfType(typeof(IForeground), typeof(DefaultForeground)) as FrameworkElement;
            foreground.Loaded += (s, e) =>
                {
                    _foreground = foreground as IForeground;
                    CheckComponents();
                };
            _foregroundPanel.Content = foreground;
        }

        private object GetInstanceOfType(Type interfaceType, Type defaultType)
        {
            object result;

            if (this.package != null)
            {
                foreach (var assembly in this.package.Assemblies)
                {
                    var type = Helper.FindInterface(assembly, interfaceType);
                    if (type != null)
                    {
                        var td = new TypeDelegator(type);
                        if (td.GetConstructors().Length != 0)
                        {
                            result = td.GetConstructors()[0].Invoke(null);
                            return result;
                        }
                    }
                }
            }

            var td2 = new TypeDelegator(defaultType);
            result = td2.GetConstructors()[0].Invoke(null);
            return result;
        }

        private DispatcherTimer _timer = new DispatcherTimer();

        public void Start()
        {
            if (_timer.IsEnabled)
            {
                _timer.Stop();
                _timer.Interval = new TimeSpan(0, Configuration.DataUpdateInterval, 0);
                _timer.Tick += (s, e) =>
                    {
                        _timer.Stop();
                        LoadSlots();
                        _timer.Interval = new TimeSpan(0, Configuration.DataUpdateInterval, 0);
                        _timer.Start();
                    };
                _timer.Start();
            }

            LoadSlots();
        }

        private void LoadSlots()
        {
            if (allSlotsDomainDataSource.IsLoadingData)
            {
                allSlotsDomainDataSource.CancelLoad();
            }

            allSlotsDomainDataSource.AutoLoad = false;
            allSlotsDomainDataSource.QueryParameters.Clear();
            System.Windows.Data.Parameter parameter = new System.Windows.Data.Parameter();
            parameter.ParameterName = "roomId";
            parameter.Value = Configuration.SelectedRoom.Id;
            allSlotsDomainDataSource.QueryParameters.Add(parameter);
            allSlotsDomainDataSource.Load();
        }

        private void ShowNextSlide()
        {
            _slidePlaceholder.HideSlideCompleted += _slidePlaceholder_HideSlideCompleted;
            _slidePlaceholder.HideSlide();
        }

        void _slidePlaceholder_HideSlideCompleted(object sender, EventArgs e)
        {
            _slidePlaceholder.HideSlideCompleted -= _slidePlaceholder_HideSlideCompleted;

            _currentSlide++;
            if (_currentSlide >= _slideStory.Slides.Count)
            {
                _currentSlide = 0;
            }
            ISlide slideHelper = _slideStory.Slides[_currentSlide] as ISlide;
            while (!slideHelper.HasContent)
            {
                _currentSlide++;
                if (_currentSlide >= _slideStory.Slides.Count)
                {
                    _currentSlide = 0;
                }
                slideHelper = _slideStory.Slides[_currentSlide] as ISlide;
            }

            FrameworkElement slide = _slideStory.Slides[_currentSlide] as FrameworkElement;

            _slidePlaceholder.Slide = slide;

            _slidePlaceholder.ShowSlideCompleted += _slidePlaceholder_ShowSlideCompleted;
            _slidePlaceholder.ShowSlide();
        }

        void _slidePlaceholder_ShowSlideCompleted(object sender, EventArgs e)
        {
            _slidePlaceholder.ShowSlideCompleted -= _slidePlaceholder_ShowSlideCompleted;
            ISlide slide = _slidePlaceholder.Slide as ISlide;

            if (_slidePlaceholder.Slide is IInteractiveSlide)
            {
                IInteractiveSlide agenda = _slidePlaceholder.Slide as IInteractiveSlide;
                agenda.Start();
            }

            if (slide.DisplayDuration > 0)
            {
                DispatcherTimer timer = new DispatcherTimer();
                timer.Interval = new TimeSpan(0, 0, slide.DisplayDuration);
                timer.Tick += (s2, e2) =>
                {
                    timer.Stop();
                    ShowNextSlide();
                };
                timer.Start();
            }
            else
            {
                slide.Finished += slide_Finished;
            }
        }

        void slide_Finished(object sender, EventArgs e)
        {
            ISlide slide = sender as ISlide;
            slide.Finished -= slide_Finished;
            ShowNextSlide();
        }

        private void allSlotsDomainDataSource_LoadedData(object sender, LoadedDataEventArgs e)
        {
            if (e.HasError)
            {
                Helper.ShowError(e.Error);
                e.MarkErrorAsHandled();
            }
            else
            {
                DigitalSignageDomainContext context = 
                    allSlotsDomainDataSource.DomainContext as DigitalSignageDomainContext;

                Configuration.AllSlots = context.AllSlots;
            }

            ShowNextSlide();
        }
        
    }
}
